import type { EventListenerConfig, PlatformEventConfig } from '../types/constants/event'
import type { PageType } from './page_handler/type'
import { HOSTNAME, logger, SelectorSyntaxType } from '../types/constants'
import { BaseDestructible } from './abstract/base_destructible'
import { PageHandler } from './page_handler'
import { ToolKit } from './utils/toolkit'

export class EventHandler extends BaseDestructible {
  protected name: string = 'EventHandler'
  isInitialized: boolean = false
  private currentPageType: PageType | null = null
  // 【注意】 一般不使用 :is() 语法，如果浏览器不支持 :is()，jQuery 会静默失败，可能会导致点击报错：unsupported pseudo: is
  private readonly eventConfig: PlatformEventConfig = {}
  private readonly nameSpace: string | null = null
  private readonly removeNativeListeners: boolean = false // 是否移除元素上的原生事件监听器

  constructor(eventConfig: PlatformEventConfig, nameSpace: string, removeNativeListeners?: boolean) {
    super()

    this.eventConfig = eventConfig
    this.nameSpace = nameSpace
    this.removeNativeListeners = removeNativeListeners || false
  }

  /**
   * 获取当前页面的事件配置
   */
  getConfig(): EventListenerConfig[] {
    this.currentPageType = PageHandler.getCurrentPageType()
    const platformConfig = this.eventConfig[HOSTNAME]

    if (!platformConfig)
      return []

    const configs = platformConfig[this.currentPageType] || []

    if (!configs.length)
      return []

    return configs
  }

  init(): void {
    // 初始化标识，销毁时需要使用
    this.isInitialized = true

    this.setupEventListeners()
  }

  /**
   * 设置事件监听器
   */
  setupEventListeners(): void {
    // 先移除可能存在的旧监听器
    this.removeEventListeners()

    this.currentPageType = PageHandler.getCurrentPageType()
    const platformConfig = this.eventConfig[HOSTNAME]

    if (!platformConfig)
      return

    const configs = platformConfig[this.currentPageType] || []

    if (!configs.length)
      return

    configs.forEach((config) => {
      const { eventType, selector, capture, context = $(document.body), handler } = config

      const namespacedEvent = `${config.eventType}.${this.nameSpace}`
      const wrappedHandler = (e: JQuery.Event) => {
        handler(e as any, config)
      }

      if (ToolKit.ui.syntax.hasSelectorSyntax(selector, SelectorSyntaxType.IS)) {
        logger.warn(`[${this.name}] 事件委托使用 :is() 选择器语法，浏览器不支持该语法`)
        return
      }

      // 支持捕获阶段的事件绑定
      if (capture) {
        // 使用原生 addEventListener 进行捕获
        context[0]?.addEventListener(
          eventType,
          wrappedHandler as unknown as EventListener,
          true,
        )
      }
      else {
        // 普通的事件委托
        context.on(
          namespacedEvent as any,
          selector,
          wrappedHandler,
        )
      }

      if (context.length > 0) {
        this.tracker.eventListeners(
          context,
          namespacedEvent,
          wrappedHandler,
        )
      }
    })

    this.printResourceStats({ prefix: `[${this.nameSpace}] ` })
  }

  /**
   * 移除事件监听器
   */
  removeEventListeners(): void {
    this.currentPageType = PageHandler.getCurrentPageType()

    try {
      const platformConfig = this.eventConfig[HOSTNAME]

      if (!platformConfig)
        return

      const configs = platformConfig[this.currentPageType] || []

      configs.forEach((config) => {
        const { eventType, selector, capture, handler, context = $('body') } = config
        const namespacedEvent = `${eventType}.${this.nameSpace}`

        if (this.removeNativeListeners)
          ToolKit.dom.removeNativeEventListeners(selector)

        if (capture) {
          // 移除捕获阶段的事件监听器
          context[0]?.removeEventListener(
            eventType,
            handler as unknown as EventListener,
            true,
          )
        }
        else {
          // 移除普通的事件委托
          context.off(namespacedEvent, selector)
        }
      })
    }
    catch (error: any) {
      logger.error(`[${this.name}] 移除事件监听器时发生错误:`, error)
    }
  }
}
